﻿using System;
using System.Collections.Generic;

namespace XchangeStreamer.Benchmark.Core
{
    public sealed class CounterInfo
    {
        #region Private Fields

        private static Dictionary<string, List<string>> countersMap;

        #endregion

        #region Const.

        static CounterInfo()
        {
            countersMap = new Dictionary<string, List<string>>();

            countersMap.Add(PerfCategories.DotNetClrLoading, new List<string>());
            countersMap[PerfCategories.DotNetClrLoading].Add(PerfCounters.BytesInLoaderHeap);
            countersMap[PerfCategories.DotNetClrLoading].Add(PerfCounters.CurrentAssemblies);
            countersMap[PerfCategories.DotNetClrLoading].Add(PerfCounters.CurrentClassesLoaded);
            countersMap[PerfCategories.DotNetClrLoading].Add(PerfCounters.TotalAssemblies);
            countersMap[PerfCategories.DotNetClrLoading].Add(PerfCounters.TotalClassesLoaded);

            countersMap.Add(PerfCategories.DotNetClrLocksAndThreads, new List<string>());
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.NoOfCurrentLogicalThreads);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.NoOfCurrentPhysicalThreads);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.NoOfCurrentRecognizedThreads);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.NoOfTotalRecognizedThreads);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.ContentionRatePerSec);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.CurrentQueueLength);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.QueueLengthPerSec);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.QueueLengthPeak);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.RateOfRecognizedThreadsPerSec);
            countersMap[PerfCategories.DotNetClrLocksAndThreads].Add(PerfCounters.TotalNoOfContentions);

            countersMap.Add(PerfCategories.DotNetClrMemory, new List<string>());
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfBytesInAllHeaps);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfGCHandles);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfGen0Collections);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfGen1Collections);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfGen2Collections);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfPinnedObjects);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfSinkBlocksInUse);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfTotalCommittedBytes);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.NoOfTotalReservedBytes);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.PercentOfTimeInGC);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.AllocatedBytesPerSec);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.FinalizationSurvivors);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.Gen0HeapSize);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.Gen0PromotedBytesPerSec);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.Gen1HeapSize);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.Gen1PromotedBytesPerSec);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.Gen2HeapSize);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.LargeObjectHeapSize);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.PromotedFinalizationMemoryFromGen0);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.PromotedMemoryFromGen0);
            countersMap[PerfCategories.DotNetClrMemory].Add(PerfCounters.PromotedMemoryFromGen1);

            countersMap.Add(PerfCategories.DotNetClrRemoting, new List<string>());
            countersMap[PerfCategories.DotNetClrRemoting].Add(PerfCounters.RemoteCallsPerSec);
            countersMap[PerfCategories.DotNetClrRemoting].Add(PerfCounters.TotalRemoteCalls);

            countersMap.Add(PerfCategories.Process, new List<string>());
            countersMap[PerfCategories.Process].Add(PerfCounters.PercentOfPrivilegedTime);
            countersMap[PerfCategories.Process].Add(PerfCounters.PercentOfProcessorTime);
            countersMap[PerfCategories.Process].Add(PerfCounters.PercentOfUserTime);
            countersMap[PerfCategories.Process].Add(PerfCounters.ElapsedTime);
            countersMap[PerfCategories.Process].Add(PerfCounters.HandleCount);
            countersMap[PerfCategories.Process].Add(PerfCounters.IoOtherBytesPerSec);
            countersMap[PerfCategories.Process].Add(PerfCounters.IoOtherOperationsPerSec);
            countersMap[PerfCategories.Process].Add(PerfCounters.PageFaultsPerSec);
            countersMap[PerfCategories.Process].Add(PerfCounters.PageFileBytes);
            countersMap[PerfCategories.Process].Add(PerfCounters.PageFileBytesPeak);
            countersMap[PerfCategories.Process].Add(PerfCounters.PoolNonpagedBytes);
            countersMap[PerfCategories.Process].Add(PerfCounters.PoolPagedBytes);
            countersMap[PerfCategories.Process].Add(PerfCounters.PriorityBase);
            countersMap[PerfCategories.Process].Add(PerfCounters.PrivateBytes);
            countersMap[PerfCategories.Process].Add(PerfCounters.ThreadCount);
            countersMap[PerfCategories.Process].Add(PerfCounters.VirtualBytes);
            countersMap[PerfCategories.Process].Add(PerfCounters.VirtualBytesPeak);
            countersMap[PerfCategories.Process].Add(PerfCounters.WorkingSet);
            countersMap[PerfCategories.Process].Add(PerfCounters.WorkingSetPrivate);
            countersMap[PerfCategories.Process].Add(PerfCounters.WorkingSetPeak);

            countersMap.Add(PerfCategories.ServiceModelService, new List<string>());
            countersMap[PerfCategories.ServiceModelService].Add(PerfCounters.Calls);
            countersMap[PerfCategories.ServiceModelService].Add(PerfCounters.CallsDuration);
            countersMap[PerfCategories.ServiceModelService].Add(PerfCounters.CallsOutstanding);
            countersMap[PerfCategories.ServiceModelService].Add(PerfCounters.CallsPerSecond);
            countersMap[PerfCategories.ServiceModelService].Add(PerfCounters.PercentOfMaxConcurrentSessions);
        }

        private CounterInfo()
        { }

        public CounterInfo(string categoryName, string counterName, string processToMonitorName)
        {
            List<string> counters;
            if (countersMap.TryGetValue(categoryName, out counters))
            {
                if (counters.Find(c => c == counterName) == null)
                {
                    throw new KeyNotFoundException(string.Format("Counter '{0}' not found in category '{1}'.", counterName, categoryName));
                }
            }
            else
            {
                throw new KeyNotFoundException(string.Format("Category '{0}' not found.", categoryName));
            }
            counters = null;

            this.CategoryName = categoryName;
            this.CounterName = counterName;
            this.ProcessToMonitorName = processToMonitorName;
        }

        #endregion

        #region Public Properties

        public string CategoryName
        {
            get;
            private set;
        }

        public string CounterName
        {
            get;
            private set;
        }

        public string ProcessToMonitorName
        {
            get;
            private set;
        }

        public float Last
        {
            get;
            internal set;
        }

        public float Average
        {
            get;
            internal set;
        }

        public float Minimum
        {
            get;
            internal set;
        }

        public float Maximum
        {
            get;
            internal set;
        }

        #endregion
    }
}
